import hashlib
import os

from bottle import Bottle, static_file, request, response, redirect
from cacheout import Cache

from src import static_dir_path, templates_dir_path
from src.python.db.model.user import User

DEFAULT_EXPIRE_SECOND = 60 * 30


class SimpleSession(object):
    def __init__(self):
        super().__init__()
        self.session = Cache()

    def create_session(self, key, value):
        """ 创建一个session, 由于 这里的session 只是为了校验是否登录服务的，所以 只有在登录后，才会有一个session  """
        self.session.set(key, value, ttl=DEFAULT_EXPIRE_SECOND)

    def assert_is_exist(self, key):
        """ 判断 是否 还在  """
        return self.session.has(key)

    def get_user_info(self, key):
        return self.session.get(key)

    def update_session(self, key, value=None):
        """
        session  在登录时 放入缓存中, 在退出时 从缓存中删除，另外每次交互都会更新过期时间，默认过期时间是 30 min
        key 是 user 的 id, value 是 user 的信息
        """
        user = value if value else self.session.get(key)
        self.session.set(key, user, ttl=DEFAULT_EXPIRE_SECOND)

    def delete_session(self, key):
        self.session.delete(key)


session = SimpleSession()

web = Bottle()


def encryption(password) -> str:
    return hashlib.md5(password.encode('utf-8')).hexdigest()


A_P_S_SECRET_KEY = encryption("all_people_sam")


def check_login_wrapper(func):
    """ 验证登陆，如果没有登陆，则跳转到login页面, 登录的话,就重新设置session过期时间 """

    def inner(*args, **kw):
        session_id = request.get_cookie("sl", secret=A_P_S_SECRET_KEY)
        if session_id and session.assert_is_exist(session_id):
            session.update_session(session_id)
            return func(*args, **kw)
        else:
            return redirect('/user/sign_in')

    return inner


###############################################
# navigate ####################################
###############################################

@web.route("/static/<filename:path>")
def static(filename):
    """ 处理静态页面 """
    return static_file(filename=filename, root=f"{static_dir_path}")


@web.route("/index")
@web.route("/")
def index():
    """ 跳转到首页 """
    return static_file(filename="index.html", root=f"{templates_dir_path}")


@web.route("/user/sign_in")
def sign_in():
    """ 跳转到登录页 """
    return static_file(filename="signin.html", root=f"{templates_dir_path}{os.sep}user")


@web.route("/user/sign_up")
def sign_up():
    """ 跳转到注册页 """
    return static_file(filename="signup.html", root=f"{templates_dir_path}{os.sep}user")


@web.route("/user/updateinfo")
@check_login_wrapper
def update_user_info():
    """ 修改个人资料 """
    return static_file(filename="updateinfo.html", root=f"{templates_dir_path}{os.sep}user")


@web.route("/index/index")
def user_center():
    """ 跳转到个人中心 """
    return static_file(filename="usercenter.html", root=f"{templates_dir_path}{os.sep}user")


@web.route("/user/loginout")
@check_login_wrapper
def login_out():
    """ 退出登录 """
    session_id = request.get_cookie("sl", secret=A_P_S_SECRET_KEY)
    session.delete_session(session_id)
    return static_file(filename="index.html", root=f"{templates_dir_path}")


###############################################
# business ####################################
###############################################

class Resp(dict):
    def __init__(self, code: int = 0, msg: str = 'success', data: dict = None):
        super().__init__()
        self.code = code
        self.data = data if data else {}
        self.msg = msg

    def to_json(self):
        return {'code': self.code, 'msg': self.msg, 'data': self.data}


def parse_request_form_4_first(d: dict, abandon_key_list: list = None):
    return {k: v[0] for k, v in d.items() if k not in abandon_key_list}


@web.route("/user/verifyAccount", method=["GET", "POST"])
def user_verify_account():
    """ 校验用户账户是否已经存在 """
    account = request.query.account
    res = User.verify_account_is_exist(account)
    if res:
        return Resp(data={"is_exist": True}).to_json()
    else:
        return Resp(data={"is_exist": False}).to_json()


@web.route("/user/register", method=["GET", "POST"])
def user_register():
    """ 用户注册 """
    d = request.forms.dict
    d = parse_request_form_4_first(d, abandon_key_list=["passwordrepeat"])
    user = User(username=d["nickname"], nickname=d["nickname"], email=d["email"], phone=d["phone"],
                password=encryption(d["password"]))
    rows = user.insert()
    if rows:
        return Resp(data={"result": "ok"}).to_json()
    else:
        return Resp(data={"result": "error"}).to_json()


@web.route("/user/login", method=["GET", "POST"])
def user_login():
    """ 用户登录 """
    d = request.query.dict
    d = parse_request_form_4_first(d, abandon_key_list=["passwordrepeat"])
    user = User.verify_by_account_and_password(d["account"], d["account"], encryption(d["password"]))
    if user:
        user = user[0]
        response.set_cookie("sl", user.id, secret=A_P_S_SECRET_KEY)
        session.create_session(user.id, user.to_dict())
        return Resp(data={"result": "ok"}).to_json()
    else:
        return Resp(data={"result": "error"}).to_json()


@web.route("/user/sessionuserinfo", method=["GET", "POST"])
def session_user_info():
    """ 通过session获取用户信息 """
    session_id = request.get_cookie("sl", secret=A_P_S_SECRET_KEY)
    if session_id and session.assert_is_exist(session_id):
        user_info = session.get_user_info(session_id)
        return Resp(data={"is_login": True, "user": user_info}).to_json()
    else:
        return Resp(data={"is_login": False}).to_json()


@web.route("/user/update", method=["GET", "POST"])
def user_info_update():
    """ 更新用户信息 """
    session_id = request.get_cookie("sl", secret=A_P_S_SECRET_KEY)
    if session_id and session.assert_is_exist(session_id):
        d = request.forms.dict
        d = parse_request_form_4_first(d, abandon_key_list=["passwordrepeat"])
        user = User(username=d["nickname"], nickname=d["nickname"], email=d["email"], phone=d["phone"],
                    password=encryption(d["password"]), id=d["userid"])
        rows = user.modify()
        if rows:
            session.delete_session(session_id)
            return Resp(data={"result": "ok"}).to_json()
        else:
            return Resp(data={"result": "error"}).to_json()
    else:
        return redirect('/user/sign_in')
